﻿using System.Collections;
using System.Diagnostics;

namespace ConfigurationDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Test.EnvironmentTest();
            Console.WriteLine("Hello, World!");
        }
    }

    public interface IChangeToken
    {
        bool HasChanged { get; }
        bool ActiveChangeCallbacks { get; }
        IDisposable RegisterChangeCallback(Action<object?> callback, object? state);
    }


    public interface IConfiguration
    {
        string this[string key] { get; set; }//获取或者设置配置值
        IConfigurationSection GetSection(string key);
        IEnumerable<IConfigurationSection> GetChildren();//获取所有子配置
        IChangeToken GetReloadToken();
    }

    public interface IConfigurationSection : IConfiguration
    {
        string Key { get; }
        string Path { get; }
        string Value { get; set; }
    }

    public interface IConfigurationRoot : IConfiguration
    {
        void Reload();
        IEnumerable<IConfigurationProvider> Providers { get; }
    }
    public interface IConfigurationBuilder
    {
        IDictionary<string, object> Properties { get; }
        IList<IConfigurationSource> Sources { get; }

        IConfigurationBuilder Add(IConfigurationSource source);
        IConfigurationRoot Build();
    }

    public interface IConfigurationSource
    {
        IConfigurationProvider Build(IConfigurationBuilder builder);
    }

    public interface IConfigurationProvider
    {
        bool TryGet(string key, out string? value);
        void Set(string key, string? value);
        IChangeToken GetReloadToken();
        void Load();
        IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string? parentPath);
    }

    //配置构建者
    public class ConfigurationBuilder : IConfigurationBuilder
    {
        private readonly List<IConfigurationSource> _sources = new();//配置源集合
        public IList<IConfigurationSource> Sources => _sources;//配置源集合

        public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>();
        //新增一个配置源
        public IConfigurationBuilder Add(IConfigurationSource source)
        {
            _sources.Add(source);
            return this;
        }
        //构建配置 
        public IConfigurationRoot Build()
        {
            var providers = new List<IConfigurationProvider>();
            //遍历所有配置源，调用Build方法，生成配置提供者，传递给最终的配置ConfigurationRoot
            foreach (IConfigurationSource source in _sources)
            {
                IConfigurationProvider provider = source.Build(this);
                providers.Add(provider);
            }
            return new ConfigurationRoot(providers);
        }
    }

    public /*abstract*/ class ConfigurationProvider : IConfigurationProvider
    {
        private ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken();
        /*protected*/
        public ConfigurationProvider()
        {
            Data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
        }
        /*protected*/
        public IDictionary<string, string?> Data { get; set; }

        public virtual bool TryGet(string key, out string? value) => Data.TryGetValue(key, out value);
        public virtual void Set(string key, string? value) => Data[key] = value;
        public virtual void Load() { }

        //获取parentPath父路径下的直接子键集合
        //假设包含 person:address:city person:address:state person:address:country person:address:school:age
        //当parentPath为person:address时，将返回city, state, country, school四个key
        public virtual IEnumerable<string> GetChildKeys(
            IEnumerable<string> earlierKeys,
            string? parentPath)
        {
            var results = new List<string>();

            if (parentPath is null)//父路径为空 直接获取所有一级key列表
            {
                foreach (KeyValuePair<string, string?> kv in Data)
                {
                    results.Add(Segment(kv.Key, 0));
                }
            }
            else
            {
                Debug.Assert(ConfigurationPath.KeyDelimiter == ":");

                foreach (KeyValuePair<string, string?> kv in Data)
                {
                    if (kv.Key.Length > parentPath.Length &&
                        kv.Key.StartsWith(parentPath, StringComparison.OrdinalIgnoreCase) &&
                        kv.Key[parentPath.Length] == ':')
                    {
                        results.Add(Segment(kv.Key, parentPath.Length + 1));
                    }
                }
            }

            results.AddRange(earlierKeys);
            results.Sort(ConfigurationKeyComparer.Comparison);

            return results;
        }

        //从索引prefixLength处开始，获取第一个:分隔符之前的字符串   假设key=person:address:city，prefixLength=0，那么返回person
        private static string Segment(string key, int prefixLength)
        {
            Debug.Assert(ConfigurationPath.KeyDelimiter == ":");
            int indexOf = key.IndexOf(':', prefixLength);
            return indexOf < 0 ? key.Substring(prefixLength) : key.Substring(prefixLength, indexOf - prefixLength);
        }

        public IChangeToken GetReloadToken()
        {
            return _reloadToken;
        }
        /*protected*/
        public void OnReload()
        {
            //将_reloadToken替换为一个新的ConfigurationReloadToken对象，并且返回上一个对象
            ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
            //调用上一个对象
            previousToken.OnReload();
        }
        public override string ToString() => GetType().Name;
    }

    //本质上维护了一个CancellationTokenSource对象，当CancellationTokenSource取消的时候
    public class ConfigurationReloadToken : IChangeToken
    {
        private readonly CancellationTokenSource _cts = new CancellationTokenSource();
        public bool ActiveChangeCallbacks { get; private set; } = true;
        public bool HasChanged => _cts.IsCancellationRequested;

        public IDisposable RegisterChangeCallback(Action<object?> callback, object? state)
        {
            return ChangeCallbackRegistrar.UnsafeRegisterChangeCallback(
                callback,
                state,
                _cts.Token,
                static s => s.ActiveChangeCallbacks = false, // Reset the flag to indicate to future callers that this wouldn't work.
                this);
        }
        public void OnReload() => _cts.Cancel();
    }

    internal static class ChangeCallbackRegistrar
    {
        internal static IDisposable UnsafeRegisterChangeCallback<T>(Action<object?> callback, object? state, CancellationToken token, Action<T> onFailure, T onFailureState)
        {
#if NETCOREAPP || NETSTANDARD2_1
            try
            {
                return token.UnsafeRegister(callback, state);
            }
            catch (ObjectDisposedException)
            {
                onFailure(onFailureState);
            }
#else
            // Don't capture the current ExecutionContext and its AsyncLocals onto the token registration causing them to live forever
            bool restoreFlow = false;
            if (!ExecutionContext.IsFlowSuppressed())
            {
                ExecutionContext.SuppressFlow();
                restoreFlow = true;
            }

            try
            {
                return token.Register(callback, state);
            }
            catch (ObjectDisposedException)
            {
                onFailure(onFailureState);
            }
            finally
            {
                // Restore the current ExecutionContext
                if (restoreFlow)
                {
                    ExecutionContext.RestoreFlow();
                }
            }
#endif
            return EmptyDisposable.Instance;
        }
    }

    //配置 维护了一个配置提供者集合 通过配置提供者集合来获取配置值
    public class ConfigurationRoot : IConfigurationRoot, IDisposable
    {
        private readonly IList<IConfigurationProvider> _providers;//配置提供者集合
        private readonly List<IDisposable> _changeTokenRegistrations;
        private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();

        public ConfigurationRoot(IList<IConfigurationProvider> providers)
        {
            //ThrowHelper.ThrowIfNull(providers);

            _providers = providers;
            _changeTokenRegistrations = new List<IDisposable>(providers.Count);
            foreach (IConfigurationProvider p in providers)
            {
                p.Load();
                _changeTokenRegistrations.Add(ChangeToken.OnChange(p.GetReloadToken, RaiseChanged));
            }
        }

        //获取配置提供者集合
        public IEnumerable<IConfigurationProvider> Providers => _providers;

        //获取配置值
        public string? this[string key]
        {
            get => GetConfiguration(_providers, key);
            set => SetConfiguration(_providers, key, value);
        }

        public IEnumerable<IConfigurationSection> GetChildren() => default;//todo this.GetChildrenImplementation(null);

        public IChangeToken GetReloadToken() => _changeToken;

        public IConfigurationSection GetSection(string key)
            => new ConfigurationSection(this, key);

        //遍历所有配置提供者，重新加载配置
        public void Reload()
        {
            foreach (IConfigurationProvider provider in _providers)
            {
                provider.Load();
            }
            RaiseChanged();
        }

        //配置发生变化时，触发事件
        private void RaiseChanged()
        {
            //重新创建一个新的ConfigurationReloadToken对象 
            ConfigurationReloadToken previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
            previousToken.OnReload();
        }

        /// <inheritdoc />
        public void Dispose()
        {
            // dispose change token registrations
            foreach (IDisposable registration in _changeTokenRegistrations)
            {
                registration.Dispose();
            }

            // dispose providers
            foreach (IConfigurationProvider provider in _providers)
            {
                (provider as IDisposable)?.Dispose();
            }
        }

        //便利所有配置提供者，获取key对应的值
        internal static string? GetConfiguration(IList<IConfigurationProvider> providers, string key)
        {
            for (int i = providers.Count - 1; i >= 0; i--)
            {
                IConfigurationProvider provider = providers[i];

                if (provider.TryGet(key, out string? value))
                {
                    return value;
                }
            }

            return null;
        }

        //便利所有配置提供者，获取key对应的值
        internal static void SetConfiguration(IList<IConfigurationProvider> providers, string key, string? value)
        {
            if (providers.Count == 0)
            {
                throw new InvalidOperationException("SR.Error_NoSources");
            }

            foreach (IConfigurationProvider provider in providers)
            {
                provider.Set(key, value);
            }
        }

        //private string DebuggerToString()
        //{
        //    return $"Sections = {ConfigurationSectionDebugView.FromConfiguration(this, this).Count}";
        //}

        //private sealed class ConfigurationRootDebugView
        //{
        //    private readonly ConfigurationRoot _current;

        //    public ConfigurationRootDebugView(ConfigurationRoot current)
        //    {
        //        _current = current;
        //    }

        //    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        //    public ConfigurationSectionDebugView[] Items => ConfigurationSectionDebugView.FromConfiguration(_current, _current).ToArray();
        //}
    }

    /// <summary>
    /// Represents a section of application configuration values.
    /// </summary>
    public class ConfigurationSection : IConfigurationSection
    {
        private readonly IConfigurationRoot _root;
        private readonly string _path;
        private string? _key;

        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        /// <param name="root">The configuration root.</param>
        /// <param name="path">The path to this section.</param>
        public ConfigurationSection(IConfigurationRoot root, string path)
        {
            //ThrowHelper.ThrowIfNull(root);
            //ThrowHelper.ThrowIfNull(path);

            _root = root;
            _path = path;
        }
        public string Path => _path;
        public string Key =>
            // Key is calculated lazily as last portion of Path
            _key ??= ConfigurationPath.GetSectionKey(_path);
        public string? Value
        {
            get
            {
                return _root[Path];
            }
            set
            {
                _root[Path] = value;
            }
        }
        public string? this[string key]
        {
            get
            {
                return _root[Path + ConfigurationPath.KeyDelimiter + key];
            }
            set
            {
                _root[Path + ConfigurationPath.KeyDelimiter + key] = value;
            }
        }
        public IConfigurationSection GetSection(string key) => _root.GetSection(Path + ConfigurationPath.KeyDelimiter + key);
        public IEnumerable<IConfigurationSection> GetChildren() => default;//todo  _root.GetChildrenImplementation(Path);
        public IChangeToken GetReloadToken() => _root.GetReloadToken();

        //private string DebuggerToString()
        //{
        //    var s = $"Path = {Path}";
        //    var childCount = Configuration.ConfigurationSectionDebugView.FromConfiguration(this, _root).Count;
        //    if (childCount > 0)
        //    {
        //        s += $", Sections = {childCount}";
        //    }
        //    if (Value is not null)
        //    {
        //        s += $", Value = {Value}";
        //        IConfigurationProvider? provider = Configuration.ConfigurationSectionDebugView.GetValueProvider(_root, Path);
        //        if (provider != null)
        //        {
        //            s += $", Provider = {provider}";
        //        }
        //    }
        //    return s;
        //}

        //private sealed class ConfigurationSectionDebugView
        //{
        //    private readonly ConfigurationSection _current;
        //    private readonly IConfigurationProvider? _provider;

        //    public ConfigurationSectionDebugView(ConfigurationSection current)
        //    {
        //        _current = current;
        //        _provider = Configuration.ConfigurationSectionDebugView.GetValueProvider(_current._root, _current.Path);
        //    }

        //    public string Path => _current.Path;
        //    public string Key => _current.Key;
        //    public string? Value => _current.Value;
        //    public IConfigurationProvider? Provider => _provider;
        //    public List<Configuration.ConfigurationSectionDebugView> Sections => Configuration.ConfigurationSectionDebugView.FromConfiguration(_current, _current._root);
        //}
    }
}


